/*
* Copyright (c) 2021 Talkweb Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "service_adapter.h"
#include "tiot_state_api.h"
#include "service_log.h"

static tiot_sysdep_portfile_t *g_config_file = NULL;
static tiot_sysdep_portfile_t g_tiot_config_file;
static tiot_sysdep_portfile_t *g_sysdep_config_file = NULL;

typedef struct {
    void *network_ctx;
    service_sysdep_socket_type_t socket_type;
    tiot_sysdep_network_cred_t *network_cred;
    char *host;
    char backup_ip[16];
    uint16_t net_port;
    uint32_t connect_timeout_ms;
} service_adapter_network_ctx_t;

void *service_adapter_network_init(void)
{
    service_adapter_network_ctx_t *ctx = g_config_file->service_sysdep_malloc(sizeof(service_adapter_network_ctx_t));
    if (ctx == NULL) {
        return NULL;
    }
    g_config_file->service_sysdep_memset(ctx, 0, sizeof(service_adapter_network_ctx_t));
    ctx->network_ctx = g_config_file->service_sysdep_network_init();

    return ctx;
}

int32_t service_adapter_network_setopt(void *ctx, service_sysdep_network_option_t option, void *data)
{
     if (ctx == NULL || data == NULL) {
         return RET_PORT_INPUT_NULL_POINTER;
     }
     if (option >= SERVICE_SYSDEP_NETWORK_MAX) {
        return RET_PORT_INPUT_OUT_RANGE;
    }
    int32_t res = RET_SUCCESS;
    service_adapter_network_ctx_t *adapter_ctx = NULL;
    adapter_ctx = (service_adapter_network_ctx_t *)ctx;
    res = g_config_file->service_sysdep_network_setopt(adapter_ctx->network_ctx, option, data);

    return res;
}

int32_t service_adapter_network_establish(void *ctx)
{
    if (ctx == NULL) {
        return RET_PORT_INPUT_NULL_POINTER;
    }

    service_adapter_network_ctx_t *ctx_tmp = (service_adapter_network_ctx_t *)ctx;

    return g_config_file->service_sysdep_network_establish(ctx_tmp->network_ctx);;
}
int32_t service_adapter_network_recv(void *ctx, uint8_t *buffer, uint32_t len, uint32_t timeout_ms,
                             service_sysdep_addr_t *addr)
{
    if (ctx == NULL) {
        return RET_PORT_INPUT_NULL_POINTER;
    }

    service_adapter_network_ctx_t *adapter_ctx = (service_adapter_network_ctx_t *)ctx;

    return g_config_file->service_sysdep_network_recv(adapter_ctx->network_ctx, buffer, len, timeout_ms, addr);
}
int32_t service_adapter_network_send(void *ctx, uint8_t *buffer, uint32_t len, uint32_t timeout_ms,
                             service_sysdep_addr_t *addr)
{
     if (ctx == NULL) {
         return RET_PORT_INPUT_NULL_POINTER;
     }

    service_adapter_network_ctx_t *adapter_ctx = (service_adapter_network_ctx_t *)ctx;

    return g_config_file->service_sysdep_network_send(adapter_ctx->network_ctx, buffer, len, timeout_ms, addr);
}

int32_t service_adapter_network_deinit(void **ctx)
{
     if (ctx == NULL || *ctx == NULL) {
         return RET_PORT_INPUT_NULL_POINTER;
     }

    service_adapter_network_ctx_t *adapter_ctx = *(service_adapter_network_ctx_t **)ctx;

    if (adapter_ctx->host != NULL) {
        g_config_file->service_sysdep_free(adapter_ctx->host);
        adapter_ctx->host = NULL;
    }

    if (adapter_ctx->network_cred != NULL) {
        g_config_file->service_sysdep_free(adapter_ctx->network_cred);
        adapter_ctx->network_cred = NULL;
    }

    g_config_file->service_sysdep_network_deinit(&adapter_ctx->network_ctx);
    g_config_file->service_sysdep_free(adapter_ctx);
    *ctx = NULL;
    log_debug("service_adapter_network_deinit\r\n");

    return RET_SUCCESS;
}

tiot_sysdep_portfile_t *tiot_sysdep_get_adapter_portfile(tiot_sysdep_portfile_t *portfile)
{
    if (portfile == NULL) {
        return NULL;
    }
    g_config_file = portfile;
    g_tiot_config_file = *portfile;
    g_tiot_config_file.service_sysdep_network_init = service_adapter_network_init;
    g_tiot_config_file.service_sysdep_network_setopt = service_adapter_network_setopt;
    g_tiot_config_file.service_sysdep_network_establish = service_adapter_network_establish;
    g_tiot_config_file.service_sysdep_network_recv = service_adapter_network_recv;
    g_tiot_config_file.service_sysdep_network_send = service_adapter_network_send;
    g_tiot_config_file.service_sysdep_network_deinit = service_adapter_network_deinit;
    return &g_tiot_config_file;
}

void tiot_sysdep_set_portfile(tiot_sysdep_portfile_t *portfile)
{
    g_sysdep_config_file = tiot_sysdep_get_adapter_portfile(portfile);
}

tiot_sysdep_portfile_t * tiot_sysdep_get_global_config(void)
{
    if (g_sysdep_config_file == NULL ||
        g_sysdep_config_file->service_sysdep_malloc == NULL ||
        g_sysdep_config_file->service_sysdep_free == NULL ||
        g_sysdep_config_file->service_sysdep_time == NULL ||
        g_sysdep_config_file->service_sysdep_sleep == NULL ||
        g_sysdep_config_file->service_sysdep_network_init == NULL ||
        g_sysdep_config_file->service_sysdep_network_setopt == NULL ||
        g_sysdep_config_file->service_sysdep_network_establish == NULL ||
        g_sysdep_config_file->service_sysdep_network_recv == NULL ||
        g_sysdep_config_file->service_sysdep_network_send == NULL ||
        g_sysdep_config_file->service_sysdep_network_deinit == NULL ||
        g_sysdep_config_file->service_sysdep_rand == NULL ||
        g_sysdep_config_file->service_sysdep_mutex_init == NULL ||
        g_sysdep_config_file->service_sysdep_mutex_lock == NULL ||
        g_sysdep_config_file->service_sysdep_mutex_unlock == NULL ||
        g_sysdep_config_file->service_sysdep_mutex_deinit == NULL) {
        return NULL;
    }
    return g_sysdep_config_file;
}


